{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1. IList 接⼝与List的区别是什么?\n",
    "- IList 泛型接⼝是 Icollection 接⼝的⼦代，并且是所有⾮泛型列表的基接⼝。 Ilist 实现有三种类别：只 读、固定⼤⼩、可变⼤⼩。 ⽆法修改只读 Ilist。 固定⼤⼩的 Ilist 不允许添加或移除元素，但允许修改现 有元素。 可变⼤⼩的 Ilist 允许添加、移除和修改元素。\n",
    "\n",
    "- IList 是个接⼝,定义了⼀些操作⽅法这些⽅法要你⾃⼰去实现，当你只想使⽤接⼝的⽅法时,这种⽅式⽐较 好.他不获取实现这个接⼝的类的其他⽅法和字段，有效的节省空间． \n",
    "\n",
    "- List 是个类型 已经实现了IList 定义的那些⽅法。\n",
    "\n",
    "``` C# \n",
    " List List11 =new List ();\n",
    "```\n",
    "\n",
    "是想创建⼀个List，⽽且需要使⽤到List的功能，进⾏相关操作。 ⽽\n",
    "\n",
    "\n",
    "``` C# \n",
    "IList IList11 =new List ();\n",
    "```\n",
    "\n",
    "只是想创建⼀个基于接⼝IList的对象的实例，只是这个接⼝是由List实现的。所以它只是希望使⽤到IList 接⼝规定的功能⽽已。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.泛型的主要约束和次要约束是什么？\n",
    "\n",
    "当⼀个泛型参数没有任何约束时，它可以进⾏的操作和运算是⾮常有限的，因为不能对实参进⾏任何类型 上的保证，这时候就需要⽤到泛型约束。泛型的约束分为：主要约束和次要约束，它们都使实参必须满⾜ ⼀定的规范，C#编译器在编译的过程中可以根据约束来检查所有泛型类型的实参并确保其满⾜约束条件。\n",
    "\n",
    "- 主要约束\n",
    "\n",
    "⼀个泛型参数⾄多拥有⼀个主要约束，主要约束可以是⼀个引⽤类型、class或者struct。如果指定⼀个引 ⽤类型（class），那么实参必须是该类型或者该类型的派⽣类型。相反，struct则规定了实参必须是⼀个 值类型。下⾯的代码展示了泛型参数主要约束："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "vscode": {
     "languageId": "csharp"
    }
   },
   "source": [
    "``` C#\n",
    "public class ClassT1<T> while T:Exception \n",
    "{\n",
    "    private T myException;\n",
    "    public ClassT1 (T t){\n",
    "        myException = t;\n",
    "    }\n",
    "    public override string ToString()\n",
    "    {\n",
    "        //主要约束保证了myException拥有的source 成员\n",
    "        return myException.Source;\n",
    "    }\n",
    "}\n",
    "\n",
    "public class ClassT2 while T : class\n",
    "{\n",
    "    private T myT;\n",
    "    // T是引用类型，可以置null\n",
    "    public void Clear(){\n",
    "        myT = null;\n",
    "    }\n",
    "}\n",
    "\n",
    "public class ClassT3<T> where T : struct \n",
    " { \n",
    "     private T myT; \n",
    "     public override string ToString() \n",
    "     { \n",
    "         // T是值类型，不会发⽣NullReferenceException异常 \n",
    "          return myT.ToString();      \n",
    "    }\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 次要约束\n",
    "\n",
    "    - 次要约束主要是指实参实现的接⼝的限定。对于⼀个泛型，可以有0到⽆限的次要约束，次要约束规定了实 参必须实现所有的次要约束中规定的接⼝。次要约束与主要约束的语法基本⼀致，区别仅在于提供的不是 ⼀个引⽤类型⽽是⼀个或多个接⼝。例如我们为上⾯代码中的ClassT3增加⼀个次要约束：\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "\n",
    "public class ClassT3<T> where T : struct, IComparable \n",
    "{ \n",
    "     ...... \n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3. 如何把⼀个array复制到arrayist⾥?\n",
    "\n",
    "``` C#\n",
    "foreach(object arr in array)\n",
    "{\n",
    "    arraylist.Add(arr);\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 4.List,Set,Map是否继承自Collection接口？\n",
    "\n",
    "- List,Set是,Map不是"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 5.Set里的元素是不能重复的，那么用什么方法来区分重复与否呢？是用==还是equals()? 他们有何区别？\n",
    "\n",
    "- Set里的元素是不能重复的，那么用iterator()来区分是否重复。equals()是判断两个Set是否相等。\n",
    "\n",
    "- equals() 和== 方法决定引用值是否指向同一对象，equals()在类中被覆盖，为的是当两个分离的对象的内容和类型相配的话，返回真值。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 6.有50万个int类型的数字，现在需要判断一下是否存在重复的数字，请简要说一下思路。\n",
    "\n",
    "1. 使用C#的List集合自带的去重方法，例如Distinct()，GroupBy()等\n",
    "\n",
    "2. 利用Dictionary的Key值唯一的特效，HastSet元素值唯一的特效 进行判断"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 7.数组有没有length()这个方法？String有没有length()这个方法？\n",
    "\n",
    "- 数组没有length()这个方法，有length属性。String有Length()这个方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 8.一个整数List 中取出最大数(找最大值)。不能用Max方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "vscode": {
     "languageId": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8\n"
     ]
    }
   ],
   "source": [
    "private static  int GetMax(List<int> list)\n",
    "{\n",
    "    int max = list[0];\n",
    "    foreach (var item in list)\n",
    "    {\n",
    "        if(item>max)\n",
    "        {\n",
    "            max = item;\n",
    "        }\n",
    "    }\n",
    "    return max;\n",
    "}\n",
    "\n",
    "var lst = new List<int>{\n",
    "    2,4,5,1,6,8,1\n",
    "};\n",
    "\n",
    "Console.WriteLine(GetMax(lst));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 9.C#异常类有哪些信息？\n",
    "\n",
    "C#中，所有异常都继承自System.Exception类，Exception类定义了C#异常应该具有的信息和方法。值得注意的属性有\n",
    "\n",
    "``` C#\n",
    "public virtual string Message{get;} //错误的信息，文字描述\n",
    "public virtual string StackTrace { get;} //发生异常的调用堆栈信息\n",
    "public System.Reflection.MethodBase TargetSite { get; } //引发这个错误的方法\n",
    "public Exception InnerException { get ;} //子异常\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 10.如何创建一个自定义异常？\n",
    "\n",
    "根据类继承原则和异常处理原则，我们可以使用一下方式来自定义一个类：\n",
    "``` C#\n",
    "public class CustomException :Exception\n",
    "{\n",
    "    \n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 11.利用IEnumerable 实现斐波那契数列生成？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1,1,2,3,"
     ]
    }
   ],
   "source": [
    "IEnumerable<int> GenerateFibonacci(int n)\n",
    "{\n",
    "    if(n>= 1)\n",
    "    {\n",
    "        yield return 1;\n",
    "    }\n",
    "    int a = 1,b=0;\n",
    "    for (int i = 2; i <=n; ++i)\n",
    "    {\n",
    "        int t =b;\n",
    "        b=a;\n",
    "        a+=t;\n",
    "        \n",
    "        yield return a;\n",
    "    }\n",
    "    \n",
    "}\n",
    "\n",
    "var a = GenerateFibonacci(4);\n",
    "foreach (var item in a)\n",
    "{\n",
    "    Console.Write(item+\",\");\n",
    "}\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 12.请利用foreach 和ref 为一个数组中的每个元素加1\n",
    "\n",
    "注意foreach 不能用var，也不能直接用int ,需要ref int ，注意arr要转换为Sapn。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "vscode": {
     "languageId": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1,2,3,4,5\n",
      "2,3,4,5,6\n"
     ]
    }
   ],
   "source": [
    "public void Add(){\n",
    "    int[] arr = {1,2,3,4,5};\n",
    "    Console.WriteLine(string.Join(\",\",arr));\n",
    "    \n",
    "    foreach(ref int v in arr.AsSpan())\n",
    "    {\n",
    "        v++;\n",
    "    }\n",
    "    Console.WriteLine(string.Join(\",\",arr));\n",
    "}\n",
    "Add();\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 13.如何针对不同的异常进⾏捕捉？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``` C#\n",
    "public class Program \n",
    "{ \n",
    "    public static void Main(string[] args) \n",
    "    {  \n",
    "        Program p = new Program(); \n",
    "        p.RiskWork();  \n",
    "        Console.ReadKey(); \n",
    "    } \n",
    "    public void RiskWork() \n",
    "    { \n",
    "        try \n",
    "        { \n",
    "             // ⼀些可能会出现异常的代码 \n",
    "        } \n",
    "        catch (NullReferenceException ex) \n",
    "        {\n",
    "            HandleExpectedException(ex); \n",
    "        }\n",
    "        catch (ArgumentException ex) \n",
    "        { \n",
    "             HandleExpectedException(ex); \n",
    "        } \n",
    "        catch (FileNotFoundException ex) \n",
    "        { \n",
    "             HandlerError(ex); \n",
    "        } \n",
    "        catch (Exception ex) \n",
    "        { \n",
    "             HandleCrash(ex); \n",
    "        } \n",
    "    }\n",
    "\n",
    " // 这⾥处理预计可能会发⽣的，不属于错误范畴的异常 \n",
    "    private void HandleExpectedException(Exception ex) \n",
    "    { \n",
    "         // 这⾥可以借助log4net写⼊⽇志 \n",
    "         Console.WriteLine(ex.Message); \n",
    "    } \n",
    "    // 这⾥处理在系统出错时可能会发⽣的，⽐较严重的异常 \n",
    "    private void HandlerError(Exception ex) \n",
    "    { \n",
    "         // 这⾥可以借助log4net写⼊⽇志\n",
    "         Console.WriteLine(ex.Message); \n",
    "         // 严重的异常需要抛到上层处理 \n",
    "         throw ex; \n",
    "    } \n",
    "    // 这⾥处理可能会导致系统崩溃时的异常 \n",
    "    private void HandleCrash(Exception ex) \n",
    "    { \n",
    "         // 这⾥可以借助log4net写⼊⽇志 \n",
    "         Console.WriteLine(ex.Message); \n",
    "         // 关闭当前程序 \n",
    "         System.Threading.Thread.CurrentThread.Abort(); \n",
    "    } \n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 14.如何避免类型转换时的异常？\n",
    "\n",
    "- 其中有些是确定可以转换的(比如将一个子类转为父类类型),而有些则是尝试性的（⽐如将基类引 ⽤的对象转换成⼦类）。当执⾏常识性转换时，我们就应该做好捕捉异常的准备。\n",
    "\n",
    "- 当⼀个不正确的类型转换发⽣时，会产⽣InvalidCastException异常，有时我们会⽤try-catch块做⼀些尝 试性的类型转换，这样的代码没有任何错误，但是性能却相当糟糕，为什么呢？异常是⼀种耗费资源的机 制，每当异常被抛出时，异常堆栈将会被建⽴，异常信息将被加载，⽽通常这些⼯作的成本相对较⾼，并 且在尝试性类型转换时，这些信息都没有意义。\n",
    "\n",
    "- 在.NET中提供了另外⼀种语法来进⾏尝试性的类型转换，那就是关键字 is 和 as 所做的⼯作。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(1) is 只负责检查类型的兼容性，并返回结果：true 和 false。→ 进⾏类型判断\n",
    "\n",
    "``` C# \n",
    "public static void Main(string[] args)\n",
    "{\n",
    "    object o = new object();\n",
    "    //执行类型兼容性检查\n",
    "    if(o is ISample){\n",
    "        //执行类型转换\n",
    "        ISample sample = (ISample)o;\n",
    "        sample.SampleShow();\n",
    "    }\n",
    "    Consloe.ReadKey();\n",
    "}\n",
    "```\n",
    "\n",
    "（2）as 不仅负责检查兼容性还会进⾏类型转换，并返回结果，如果不兼容则返回 null 。→ ⽤于类型转 型\n",
    "``` C# \n",
    "public static void Main(string[] args)\n",
    "{\n",
    "    object o = new object();\n",
    "    //执行类型兼容性检查\n",
    "    ISample sample = o as ISample;\n",
    "    if(sample != null){\n",
    "        sample.SampleShow();\n",
    "    }\n",
    "    Consloe.ReadKey();\n",
    "}\n",
    "```\n",
    "\n",
    "两者的共同之处都在于：不会抛出异常！综上⽐较，as 较 is 在执⾏效率上会好⼀些，在实际开发中应该 量才⽽⽤，在只进⾏类型判断的应⽤场景时，应该多使⽤ is ⽽不是 as"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 15.Serializable特性有什么作⽤？\n",
    "\n",
    "通过上⾯的流类型可以⽅便地操作各种字节流，但是如何把现有的实例对象转换为⽅便传输的字节流，就 需要使⽤序列化技术。对象实例的序列化，是指将实例对象转换为可⽅便存储、传输和交互的流。在.NET 中，通过Serializable特性提供了序列化对象实例的机制，当⼀个类型被申明为Serializable后，它就能被 诸如BinaryFormatter等实现了IFormatter接⼝的类型进⾏序列化和反序列化。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 16.委托是什么\n",
    "\n",
    "- 委托是寻址的.net版本。在C++中，函数指针只不过是一个指向内存位置的指针，它不是类型安全的。我们无法判断这个指针实际指向什么，像参数和返回类型等项更无从知晓了。\n",
    "\n",
    "- 而.NET委托完全不同，委托是类型安全的类，它定义了返回类型和参数的类型。委托类不仅包含对方法的不同引用，也可以包含对方法的引用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 17.如何自定义委托？\n",
    "\n",
    "声明一个委托类型，他的实例引用一个方法，该方法获取一个int参数，返回void\n",
    "\n",
    "``` C# \n",
    "public delegate void Feedback(int num);\n",
    "```\n",
    "\n",
    "理解委托的一个要点是他们的安全性非常高。在定义委托时，必须给出他所表示的方法的签名和返回类型等全部细节。\n",
    "\n",
    "理解委托的一种比较好的方法时把委托当作一件事情：他给方法的签名和返回类型指定名称。\n",
    "\n",
    "其语法类似于⽅法的定义，需要在定义⽅法的前⾯加上delegate关键字。定义委托基本上就是定义⼀个新 的类，所以可以在任何地⽅定义类的相同地⽅定义委托，也就是说，可以在另⼀个类的内部定义，也可以 在任何类的外部定义，还可以在名称控件中把委托定义为定义为顶层对象。访问修饰符可以是 public/private/protected等。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 18 .NET默认的委托类型有哪⼏种？\n",
    "\n",
    "1. Action<T>\n",
    "    - 泛型委托标识引用一个void返回类型的方法。这个委托类存在16种重载方法。\n",
    "    - 例如Action<in T1,in T2>调用没有参数的方法\n",
    "    \n",
    "2. Func<T>\n",
    "    - Func调用带返回类型的方法。一共有16种重载方法。    \n",
    "    - 例如Func委托类型可以调⽤带返回类型且⽆参数的⽅法，Func<in T,out TResult>委托类型调⽤带有4个参数和⼀个返回类型的⽅法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 19.什么是泛型委托？\n",
    "Action就是泛型委托。\n",
    "\n",
    "- 注意事项：\n",
    "\n",
    "    - 建议尽量使⽤这些委托类型，⽽不是在代码中定义更多的委托类型。这样可以减少系统中的类型数⽬，同 时简化编码\n",
    "    - 如果需要使⽤ref或out关键字，以传引⽤的⽅式传递⼀个参数，就可能不得不定义⾃⼰的委托： \n",
    "    ```\n",
    "    delegate void Test(ref int i)\n",
    "    ```\n",
    "    - 如果委托要通过C#的params关键字获取可变数量的额参数，要为委托的任何桉树指定默认值，或者要 对委托的泛型类型参数进⾏约束，也必须定义⾃⼰的委托类型\n",
    "\n",
    "    ```\n",
    "    delegate void EventHandler(Object sender, TEventArgs e) where TEventArgs : EventArgs;\n",
    "    ```\n",
    "    - 使⽤获取泛型实参和返回值的委托时，可利⽤逆变与协变。逆变：⽗类转换为⼦类；协变：⼦类转换为 ⽗类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 20. 什么是匿名⽅法?\n",
    "\n",
    "匿名方法时用做委托的参数的一段代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "vscode": {
     "languageId": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "//匿名方法，例1\n",
    "Func<int,int> anon = delegate(int i)\n",
    "{\n",
    "    i=i+1;\n",
    "    return i;\n",
    "};\n",
    "//输出2\n",
    "Console.WriteLine(anon(1));\n",
    "\n",
    "//匿名方法，例2\n",
    "Action<int> anon2 = delegate(int i)\n",
    "{\n",
    "    i=i+1;\n",
    "};\n",
    "//输出2\n",
    "Console.WriteLine(anon(1));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 匿名方法的作用\n",
    "    - 可以使用匿名函数来初始化命名委托[无需取名字的委托]，或传递命名委托（而不是命名委托类型,传递一个方法块，而不是 委托类型）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 21. 什么是闭包？\n",
    "\n",
    "- 通过Lambda表达式可以访问Lambda表达式块外部的变量，这成为闭包\n",
    "- 当引用外部变量时，需要注意，外部变量变换时，lambda 表达式的结果也可能会随着外部变量变化而变化\n",
    "\n",
    "    - 如下面的例子：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "vscode": {
     "languageId": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6\n",
      "11\n"
     ]
    }
   ],
   "source": [
    "int y = 5;\n",
    "Func<int,int> lambda = x=>x+y;\n",
    "Console.WriteLine(lambda(1));\n",
    "y=10;\n",
    "Console.WriteLine(lambda(1));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 22. EF(Entity Framework)是什么？\n",
    "\n",
    "- 实体框架EF 是ADO.NET 中的一组支持开发面向数据的软件应用程序的技术，是微软的一个ORM框架。\n",
    "- 主要有三种方法：\n",
    "    - Database FirstDatabase First 模式\n",
    "    - 我们称之为“数据库优先”，前提是你的应⽤已经有相应的数据库，你可以使⽤EF设计⼯具根据数据库⽣成 数据数据类，你可以使⽤Visual Studio模型设计器修改这些模型之间对应关系。\n",
    "- [参考链接](https://blog.csdn.net/u011854789/article/details/72783902) Model FirstModel First我们称 之为“模型优先”，这⾥的模型指的是“ADO.NET Entity Framework Data Model”，此时你的应⽤并没有 设计相关数据库，在Visual Studio中我们通过设计对于的数据模型来⽣成数据库和数据类。\n",
    "- Code FirstCode First 模式我们称之为“代码优先”模式，是从EF4.1开始新建加⼊的功能。\n",
    "    - 使⽤Code First模式进⾏EF开发时开发⼈员只需要编写对应的数据类（其实就是领域模型的实现过程）， 然后⾃动⽣成数据库。这样设计的好处在于我们可以针对概念模型进⾏所有数据操作⽽不必关⼼数据的存 储关系，使我们可以更加⾃然的采⽤⾯向对象的⽅式进⾏⾯向数据的应⽤程序开发。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 23. 什么是ORM?\n",
    "- ORM 指的是面向对象的对象模型和关系型数据库的数据结构之间的互相转换。\n",
    "    -（表实体跟表之间的互相转换）\n",
    "- ORM框架很多，EF框架是ORM框架的其中一种，是实现ORM思想的框架。\n",
    "    - O=>表实体\n",
    "    - M=>映射关系\n",
    "    - R=>数据库.表"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 24.为什么⽤EF⽽不⽤原⽣的ADO.NET?\n",
    "\n",
    "1. 极大的提高开发效率：EF是微软自己的产品，开发中代码都是强类型的，代码效率非常高，自动化程度非常高，命令式编程。\n",
    "\n",
    "2. EF提供的模型设计器非常强大，不仅仅带来了设计数据库的革命，也附带来的自动化模型代码的功能也极大的提高开发和架构设计的效率。\n",
    "\n",
    "3. EF跨数据支持的是ORM框架主要功能点之一，带来的是可以通过仅仅改变配置就可以跨数据库的能力。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 25.如何提⾼LINQ性能问题？\n",
    "\n",
    "提升从数据库中拿数据的速度，可以参考以下几种方法;\n",
    "\n",
    "1. 在数据库中的表中定义合适的索引和键\n",
    "\n",
    "2. 只获得你需要的列(使用ViewModel或者改进你的查询)和行(使用IQueryable)\n",
    "\n",
    "3. 尽可能使用一条查询而不是多条\n",
    "\n",
    "4. 只为了展示数据，而不进行后续修改时，可以使用AsNoTracking。它不会影响生成的SQL,但它可以令系统少维护很数据，从而提高性能。\n",
    "\n",
    "5. 使用Reshaper等工具，它可能会在你写出较差的代码时给出提醒"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 26.什么是协变和逆变?\n",
    "\n",
    "可变性是以⼀种类型安全的⽅式，将⼀个对象作为另⼀个对象来使⽤。其对应的术语则是不变性 （invariant）。\n",
    "\n",
    "- 可变性:\n",
    "    - 可变性是以⼀种类型安全的⽅式，将⼀个对象作为另⼀个对象来使⽤。例如对普通继承中的可变性：若某 ⽅法声明返回类型为Stream，在实现时可以返回⼀个MemoryStream。可变性有两种类型：协变和逆变。\n",
    "\n",
    "- 协变性：\n",
    "    - 可以建⽴⼀个较为⼀般类型的变量，然后为其赋值，值是⼀个较为特殊类型的变量。例如：\n",
    "    ``` C# \n",
    "    string str = \"test\"; \n",
    "    // An object of a more derived type is assigned to an object of a \n",
    "    less derived type. \n",
    "    object obj = str;\n",
    "    ```\n",
    "    因为string肯定是⼀个object，所以这样的变化⾮常正常。\n",
    "\n",
    "- 逆变性：\n",
    "    - 在上⾯的例⼦中，我们⽆法将str和⼀个新的object对象画等号。如果强⾏要实现的话，只能这么 ⼲：\n",
    "    ``` C# \n",
    "    string s = (string) new object();\n",
    "    ```\n",
    "    但这样还是会在运⾏时出错。这也告诉我们，逆变性是很不正常的。\n",
    "\n",
    "- 泛型的协变与逆变:\n",
    "    - 协变性和out关键字搭配使⽤，⽤于向调⽤者返回某项操作的值。例如下⾯的接⼝仅有⼀个⽅法，就是⽣产 ⼀个T类型的实例。那么我们可以传⼊⼀个特定类型。如我们可以将IFactory视为IFactory。这也适⽤于 Food的所有⼦类型。（即将其视为⼀个更⼀般类型的实现）\n",
    "    ``` C#\n",
    "    interface IFactory<T>\n",
    "    {\n",
    "        T CreateInstance();\n",
    "    }\n",
    "    ```\n",
    "\n",
    "    - 逆变性则相反，和in关键字搭配使⽤，指的是API将会消费值，⽽不是⽣产值。此时⼀般类型出现在参数 中：\n",
    "    ``` C# \n",
    "    interface IPrint<T>\n",
    "    {\n",
    "        void Print(T value);\n",
    "    }\n",
    "    ```\n",
    "    - 这意味着如果我们实现了IPrint< Code >，我们就可以将其当做IPrint< CsharpCode >使⽤。（即将其视 为⼀个更具体类型的实现）\n",
    "    - 这意味着如果我们实现了IPrint< Code >，我们就可以将其当做IPrint< CsharpCode >使⽤。（即将其视 为⼀个更具体类型的实现）\n",
    "    ``` C#\n",
    "    interface IStorage<T>\n",
    "    {\n",
    "        byte[] Serialize(T value);\n",
    "        T Deserialize(byte[] data);\n",
    "    }\n",
    "    ```\n",
    "    - 这个接⼝是不变体。我们不能将它视为⼀个更具体或更⼀般类型的实现。 \n",
    "    - 假设有如下继承关系People –> Teacher，People –> Student。 \n",
    "    - 如果我们以协变的⽅式使⽤（假设你建⽴了⼀个IStorage< Teacher >的实例，并将其视为IStorage）则 我们可能会在调⽤Serialize时产⽣异常，因为Serialize⽅法不⽀持协变（如果参数是People的其他⼦类， 例如Student，则IStorage< Teacher >将⽆法序列化Student）。 \n",
    "    - 如果我们以逆变的⽅式使⽤（假设你建⽴了⼀个IStorage的实例，并将其视为IStorage< Teacher >）， 则我们可能会在调⽤Deserialize时产⽣异常，因为Deserialize⽅法不⽀持逆变，它只能返回People不能 返回Teacher。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 27.什么是IEnumerable？\n",
    "- IEnumerable及IEnumerable的泛型版本IEnumerable是⼀个接⼝，它只含有⼀个⽅法GetEnumerator。 Enumerable这个静态类型含有很多扩展⽅法，其扩展的⽬标是IEnumerable。 \n",
    "- 实现了这个接⼝的类可以使⽤Foreach关键字进⾏迭代（迭代的意思是对于⼀个集合，可以逐⼀取出元素 并遍历之）。实现这个接⼝必须实现⽅法GetEnumerator。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "file_extension": ".cs",
   "mimetype": "text/x-csharp",
   "name": "C#",
   "pygments_lexer": "csharp",
   "version": "10.0"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "61a57a4b5406d2de388e2f91097d4e4bcd7d5f4a46f53a795aa28a02eed27fc5"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
